#pragma once

#include <list>
#include <memory>
#include <mutex>
#include <condition_variable>

// 对象池模式(Object Pool Pattern)
// 高效管理可重用的对象集合
// 创建型设计模式, 它通过存储一系列已经初始化的对象来避免频繁创建和销毁对象所带来的性能开销;
// 特别适用于对象创建成本高或频繁请求相同类型对象的场景

#define DEFAULT_OBJECT_POOL_INIT_NUM 0    // 对象池初始时预创建对象的数量
#define DEFAULT_OBJECT_POOL_MAX_NUM  4    // 对象池允许的最大对象数量, 默认为4
#define DEFAULT_OBJECT_POOL_TIMEOUT  3000 //  尝试从池中借用对象时的超时时间 ms

// 这是一个通用工厂类模板, 用于生成特定类型的对象。
// 默认实现是通过new操作符创建类型T的对象, 但这个工厂类可以被用户自定义以实现更复杂的对象创建逻辑。
template <class T>
class ObjectFactory
{
public:
    static T *create()
    {
        return new T;
    }
};

template <class T, class TFactory = ObjectFactory<T>>
class ObjectPool
{
public:
    ObjectPool(
        size_t init_num = DEFAULT_OBJECT_POOL_INIT_NUM,
        size_t max_num = DEFAULT_OBJECT_POOL_MAX_NUM,
        size_t timeout = DEFAULT_OBJECT_POOL_TIMEOUT) :
        _max_num(max_num), _timeout(timeout)
    {
        for (size_t i = 0; i < init_num; ++i)
        {
            T *p = TFactory::create();
            if (p)
            {
                objects_.push_back(std::shared_ptr<T>(p));
            }
        }
        _object_num = objects_.size();
    }

    ~ObjectPool()
    {
    }

    size_t ObjectNum() // 对象总数
    {
        return _object_num;
    }

    size_t IdleNum() // 空闲对象数
    {
        return objects_.size();
    }

    size_t BorrowNum() // 已借出对象数
    {
        return ObjectNum() - IdleNum();
    }

    std::shared_ptr<T> TryBorrow() // 尝试无等待地从池中借用一个对象
    {
        std::shared_ptr<T> pObj = NULL;
        std::lock_guard<std::mutex> locker(mutex_);
        if (!objects_.empty())
        {
            pObj = objects_.front();
            objects_.pop_front();
        }
        return pObj;
    }

    std::shared_ptr<T> Borrow() // 在没有空闲对象时, 根据配置可能等待指定时间尝试获取对象, 或者在达到最大对象限制时返回NULL。
    {
        std::shared_ptr<T> pObj = TryBorrow();
        if (pObj)
        {
            return pObj;
        }

        std::unique_lock<std::mutex> locker(mutex_);
        if (_object_num < _max_num)
        {
            ++_object_num;
            // NOTE: unlock to avoid TFactory::create block
            mutex_.unlock();
            T *p = TFactory::create();
            mutex_.lock();
            if (!p)
            {
                --_object_num;
            }
            return std::shared_ptr<T>(p);
        }

        if (_timeout > 0)
        {
            std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout));
            if (status == std::cv_status::timeout)
            {
                return NULL;
            }
            if (!objects_.empty())
            {
                pObj = objects_.front();
                objects_.pop_front();
                return pObj;
            }
            else
            {
                // WARN: No idle object
            }
        }
        return pObj;
    }

    void Return(std::shared_ptr<T> &pObj) // 归还对象到池中
    {
        if (!pObj)
        {
            return;
        }
        std::lock_guard<std::mutex> locker(mutex_);
        objects_.push_back(pObj);
        cond_.notify_one();
    }

    bool Add(std::shared_ptr<T> &pObj) // 增加对象到对象池
    {
        std::lock_guard<std::mutex> locker(mutex_);
        if (_object_num >= _max_num)
        {
            return false;
        }
        objects_.push_back(pObj);
        ++_object_num;
        cond_.notify_one();
        return true;
    }

    bool Remove(std::shared_ptr<T> &pObj) // 从对象池删除对象
    {
        std::lock_guard<std::mutex> locker(mutex_);
        auto iter = objects_.begin();
        while (iter != objects_.end())
        {
            if (*iter == pObj)
            {
                iter = objects_.erase(iter);
                --_object_num;
                return true;
            }
            else
            {
                ++iter;
            }
        }
        return false;
    }

    void Clear()
    {
        std::lock_guard<std::mutex> locker(mutex_);
        objects_.clear();
        _object_num = 0;
    }

    size_t _object_num;
    size_t _max_num;
    size_t _timeout;

private:
    std::list<std::shared_ptr<T>> objects_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

// 智能指针包装类, 用于自动管理从对象池中借用和归还对象的过程。
// 通过RAII(Resource Acquisition Is Initialization)机制, 在对象生命周期结束时自动将对象归还给对象池, 简化了资源管理并减少了资源泄露的风险。
template <class T, class TFactory = ObjectFactory<T>>
class PoolObject
{
public:
    typedef ObjectPool<T, TFactory> PoolType;

    PoolObject(PoolType &pool) :
        pool_(pool)
    {
        sptr_ = pool_.Borrow();
    }

    ~PoolObject()
    {
        if (sptr_)
        {
            pool_.Return(sptr_);
        }
    }

    PoolObject(const PoolObject<T> &) = delete;
    PoolObject<T> &operator=(const PoolObject<T> &) = delete;

    T *get()
    {
        return sptr_.get();
    }

    operator bool()
    {
        return sptr_.get() != NULL;
    }

    T *operator->()
    {
        return sptr_.get();
    }

    T operator*()
    {
        return *sptr_.get();
    }

private:
    PoolType &pool_;
    std::shared_ptr<T> sptr_;
};
